{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## PyTorch–深度学习全栈工程师进阶案例实战（第十期）第4课书面作业\n",
    "学号：115539\n",
    "\n",
    "**作业内容：**  \n",
    "1. 跑通网盘中的Resnet.py  \n",
    "2. 实现LinearBottleNeck Class"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第1题\n",
    "跑通网盘中的Resnet.py  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "from torchvision import datasets, transforms, models\n",
    "from torch.utils.data import DataLoader\n",
    "import time\n",
    "from tqdm import tqdm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "print(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "transform = transforms.Compose([\n",
    "    transforms.Resize((224,224)),\n",
    "    # transforms.RandomResizedCrop(224),\n",
    "    transforms.RandomRotation(20),\n",
    "    transforms.RandomHorizontalFlip(p=0.5),\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "transform_tst = transforms.Compose([\n",
    "    transforms.Resize((224,224)),\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "train_ds = datasets.CIFAR10(root='./', train=True, transform=transform, download=False)\n",
    "test_ds = datasets.CIFAR10(root='./', train=False, transform=transform_tst, download=False)\n",
    "\n",
    "batch_size = 64\n",
    "\n",
    "train_loader = DataLoader(dataset=train_ds, batch_size=batch_size, shuffle=True)\n",
    "test_loader = DataLoader(dataset=test_ds, batch_size=batch_size, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "import resnet\n",
    "model = resnet.ResNet(out_dim=10)\n",
    "# model.to(device)\n",
    "# print(model)\n",
    "loss_fn = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(),lr=0.0001)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(model, device, loader, optimizer, loss_fn, epoch):\n",
    "    # print('Epochs: ', epoch)\n",
    "    model.to(device)\n",
    "    correct = 0\n",
    "    L = len(loader.dataset)\n",
    "    model.train()\n",
    "    with tqdm(loader, unit=\"batch\") as tepoch: \n",
    "        for data, target in tepoch:              \n",
    "            tepoch.set_description(f\"Epoch {epoch}\") \n",
    "            data, target = data.to(device), target.to(device)\n",
    "            optimizer.zero_grad()                                     \n",
    "            output = model(data)                                       \n",
    "            losstr = loss_fn(output,target)                             \n",
    "            losstr.backward()                                         \n",
    "            optimizer.step()                                         \n",
    "    \n",
    "            predict = output.argmax(dim=1, keepdim=True)                  \n",
    "            correct = predict.eq(target.view_as(predict)).sum().item() \n",
    "\n",
    "            accuracy = correct/len(data)\n",
    "            tepoch.set_postfix(loss=losstr.item(), accuracy='{:.3f}'.format(accuracy)) \n",
    "\n",
    "def test(model, device, loader, loss_fn, epoch):\n",
    "    model.to(device)\n",
    "    correct = 0\n",
    "    L = len(loader.dataset)\n",
    "    model.eval()\n",
    "    with tqdm(loader, unit=\"batch\") as tepoch: \n",
    "        for data, target in tepoch:              \n",
    "            tepoch.set_description(f\"Epoch {epoch}\") \n",
    "            data, target = data.to(device), target.to(device)                                  \n",
    "            output = model(data)                                                                                                 \n",
    "            losstr = loss_fn(output,target)\n",
    "            predict = output.argmax(dim=1, keepdim=True)                  \n",
    "            correct = predict.eq(target.view_as(predict)).sum().item() \n",
    "\n",
    "            accuracy = correct/len(data)\n",
    "            tepoch.set_postfix(loss=losstr.item(), accuracy='{:.3f}'.format(accuracy)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Epoch 0: 100%|██████████| 782/782 [05:17<00:00,  2.46batch/s, accuracy=1.000, loss=0.103] \n",
      "Epoch 1: 100%|██████████| 782/782 [05:12<00:00,  2.50batch/s, accuracy=0.938, loss=0.0666]\n",
      "Epoch 2: 100%|██████████| 782/782 [05:09<00:00,  2.53batch/s, accuracy=1.000, loss=0.158] \n",
      "Epoch 3: 100%|██████████| 782/782 [05:09<00:00,  2.52batch/s, accuracy=1.000, loss=0.0381]\n",
      "Epoch 4: 100%|██████████| 782/782 [05:09<00:00,  2.53batch/s, accuracy=0.875, loss=0.204] \n",
      "Epoch 5: 100%|██████████| 782/782 [05:11<00:00,  2.51batch/s, accuracy=0.812, loss=0.857] \n",
      "Epoch 6: 100%|██████████| 782/782 [05:14<00:00,  2.49batch/s, accuracy=0.938, loss=0.387]  \n",
      "Epoch 7: 100%|██████████| 782/782 [05:14<00:00,  2.49batch/s, accuracy=1.000, loss=0.00824]\n",
      "Epoch 8: 100%|██████████| 782/782 [05:14<00:00,  2.49batch/s, accuracy=1.000, loss=0.0057] \n",
      "Epoch 9: 100%|██████████| 782/782 [05:14<00:00,  2.49batch/s, accuracy=0.812, loss=0.356]  \n"
     ]
    }
   ],
   "source": [
    "for epoch in range(10):\n",
    "    train(model,device,train_loader,optimizer,loss_fn,epoch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.save(model.state_dict(), 'resnet-50.pth')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<All keys matched successfully>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.load_state_dict(torch.load('resnet-50.pth'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Epoch 0: 100%|██████████| 157/157 [00:25<00:00,  6.17batch/s, accuracy=0.812, loss=0.344]\n"
     ]
    }
   ],
   "source": [
    "test(model,device,test_loader,loss_fn, 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第2题\n",
    "实现LinearBottleNeck Class"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实现如下：  \n",
    "```python\n",
    "class LinearBottleNeck(nn.Module):\n",
    "\n",
    "    def __init__(self, in_channels, out_channels, stride, t=6, class_num=100):\n",
    "        super().__init__()\n",
    "        self.in_channels = in_channels\n",
    "        self.out_channels = out_channels\n",
    "        self.stride = stride\n",
    "        self.residual = nn.Sequential(\n",
    "            nn.Conv2d(in_channels,out_channels*t,1),\n",
    "            nn.ReLU6(inplace=True),\n",
    "            nn.Conv2d(out_channels*t, out_channels*t, 3, stride, padding=1),\n",
    "            nn.ReLU6(inplace=True),\n",
    "            nn.Conv2d(out_channels*t,out_channels,1)\n",
    "        )\n",
    "        pass\n",
    "\n",
    "    def forward(self, x):\n",
    "        residual = self.residual(x)\n",
    "\n",
    "        if self.stride == 1 and self.in_channels == self.out_channels:\n",
    "            residual += x\n",
    "\n",
    "        return residual\n",
    "\n",
    "class MobileNetV2(nn.Module):\n",
    "\n",
    "    def __init__(self, class_num=100):\n",
    "        super().__init__()\n",
    "\n",
    "        self.pre = nn.Sequential(\n",
    "            nn.Conv2d(3, 32, 3,2, padding=1), #<----修改\n",
    "            nn.BatchNorm2d(32),\n",
    "            nn.ReLU6(inplace=True)\n",
    "        )\n",
    "        ...\n",
    "```\n",
    "\n",
    "试一下执行结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MobileNetV2(\n",
      "  (pre): Sequential(\n",
      "    (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "    (2): ReLU6(inplace=True)\n",
      "  )\n",
      "  (stage1): LinearBottleNeck(\n",
      "    (residual): Sequential(\n",
      "      (0): Conv2d(32, 16, kernel_size=(1, 1), stride=(1, 1))\n",
      "      (1): ReLU6(inplace=True)\n",
      "      (2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "      (3): ReLU6(inplace=True)\n",
      "      (4): Conv2d(16, 16, kernel_size=(1, 1), stride=(1, 1))\n",
      "    )\n",
      "  )\n",
      "  (stage2): Sequential(\n",
      "    (0): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(16, 144, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(144, 144, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(144, 24, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (1): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(24, 144, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(144, 144, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(144, 24, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "  )\n",
      "  (stage3): Sequential(\n",
      "    (0): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(24, 192, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(192, 192, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (1): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(32, 192, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(192, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (2): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(32, 192, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(192, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "  )\n",
      "  (stage4): Sequential(\n",
      "    (0): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(32, 384, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(384, 384, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (1): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (2): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (3): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "  )\n",
      "  (stage5): Sequential(\n",
      "    (0): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(64, 576, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(576, 576, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (1): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(96, 576, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(576, 576, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (2): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(96, 576, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(576, 576, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "  )\n",
      "  (stage6): Sequential(\n",
      "    (0): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(96, 960, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(960, 960, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(960, 160, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (1): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(160, 960, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(960, 960, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(960, 160, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "    (2): LinearBottleNeck(\n",
      "      (residual): Sequential(\n",
      "        (0): Conv2d(160, 960, kernel_size=(1, 1), stride=(1, 1))\n",
      "        (1): ReLU6(inplace=True)\n",
      "        (2): Conv2d(960, 960, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (3): ReLU6(inplace=True)\n",
      "        (4): Conv2d(960, 160, kernel_size=(1, 1), stride=(1, 1))\n",
      "      )\n",
      "    )\n",
      "  )\n",
      "  (stage7): LinearBottleNeck(\n",
      "    (residual): Sequential(\n",
      "      (0): Conv2d(160, 1920, kernel_size=(1, 1), stride=(1, 1))\n",
      "      (1): ReLU6(inplace=True)\n",
      "      (2): Conv2d(1920, 1920, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "      (3): ReLU6(inplace=True)\n",
      "      (4): Conv2d(1920, 320, kernel_size=(1, 1), stride=(1, 1))\n",
      "    )\n",
      "  )\n",
      "  (conv1): Sequential(\n",
      "    (0): Conv2d(320, 1280, kernel_size=(1, 1), stride=(1, 1))\n",
      "    (1): BatchNorm2d(1280, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "    (2): ReLU6(inplace=True)\n",
      "  )\n",
      "  (conv2): Conv2d(1280, 100, kernel_size=(1, 1), stride=(1, 1))\n",
      ")\n",
      "torch.Size([1, 100])\n"
     ]
    }
   ],
   "source": [
    "import mobilenetv2 as mnv2\n",
    "import torch\n",
    "\n",
    "model = mnv2.MobileNetV2()\n",
    "print(model)\n",
    "\n",
    "a = torch.Tensor(1,3,224,224)\n",
    "b = model(a)\n",
    "print(b.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "5a9b5a6d2646af59ee527d292336757320033f7238f9c553b4d557a8df7d0f99"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
